﻿using BCCommon;
using BCCommon.TMS.Driver;
using BCData.TMS.Driver;
using BCData.TMS.Driver.DriverExamine;
using BCData.TMS.Driver.DriverLearnDatum;
using BCDto.TMS.Driver.DriverExamine;
using BCDto.TMS.Driver.DriverExamLearn;
using BCDto.TMS.Driver.DriverLearnDatum;
using BCEntity.TMS.Driver.DriverExamine;
using BCService.Utils;
using System;
using System.Collections.Generic;
using System.Linq;

namespace BCService.TMS.Driver.DriverExamLearn
{
    public class DriverExamLearnService : IDriverExamLearnService
    {
        protected readonly IDriverLearnDatumData driverLearnDatumData;
        protected readonly IDriverExamineMarkData examineMarkData;
        protected readonly IDriverData driverData;
        protected readonly IRedisService redisService;
        protected readonly IDriverExamineTestQuestionData examineTestquestionsData;
        protected readonly IDriverExamineTestQuestionAnswerData testQuestionAnswerData;
        protected readonly string entityName = "DriverLearnDatumEntity";
        protected readonly IDriverExaminePaperData paperData;
        private const string LEARN_DATUMS_KEY = "Cached-LearnDatums";
        protected readonly string cacheDriverKeyFormat = "DriverUserViewEntity@UserId:{0}";

        public DriverExamLearnService(IDriverLearnDatumData driverLearnDatumData, IRedisService redisService, IDriverData driverData, IDriverExamineMarkData examineMarkData, IDriverExamineTestQuestionData examineTestquestionsData, IDriverExamineTestQuestionAnswerData testQuestionAnswerData, IDriverExaminePaperData paperData)
        {
            this.driverLearnDatumData = driverLearnDatumData;
            this.redisService = redisService;
            this.driverData = driverData;
            this.examineMarkData = examineMarkData;
            this.examineTestquestionsData = examineTestquestionsData;
            this.testQuestionAnswerData = testQuestionAnswerData;
            this.paperData = paperData;
        }

        /// <summary>
        /// 获取一组学习资料信息列表
        /// </summary>
        /// <param name="datumTopic">学习标题</param>
        /// <param name="answerContent">学习内容</param>
        /// <param name="pageIndex">分页页码</param>
        /// <param name="pageSize">页数</param>
        /// <param name="role">司机角色类型</param>
        /// <returns></returns>
        public PageableList<DriverLearnDatumDto> GetDriverLearnDatums(string datumTopic, string answerContent, int pageIndex, int pageSize, DriverRoleType role)
        {
            var queryResult = driverLearnDatumData.GetDriverLearnDatumsAsync(datumTopic, answerContent, role, pageIndex, pageSize).GetAwaiter().GetResult();
            return new PageableList<DriverLearnDatumDto>
            {
                Items = queryResult.Item1.As<IEnumerable<DriverLearnDatumDto>>(),
                Count = queryResult.Item2,
                PageIndex = pageIndex,
                PageSize = pageSize
            };
        }

        /// <summary>
        /// 获取当前司机的考试成绩
        /// </summary>
        /// <param name="driverId">当前登录的司机Id</param>
        /// <returns></returns>
        public DriverExamineMarkDto GetExamineMarkByDriverId(long driverId)
        {
            var driver = driverData.GetDriverByIdAsync(driverId).GetAwaiter().GetResult();
            if (driver == null)
            {
                throw new ArgumentException("司机信息不存在");
            }

            DriverExamineMarkEntity entity = examineMarkData.GetExamineMarkByDriverIdAsync(driverId).GetAwaiter().GetResult();
            if (entity == null)
            {
                return null;
            }
            return entity.As<DriverExamineMarkDto>();
        }

        /// <summary>
        /// 获取一组考试试题信息列表
        /// </summary>
        /// <param name="role"></param>
        /// <returns></returns>
        public PageableList<DriverExamineTestQuestionDto> GetExamineTestquestions(DriverRoleType role)
        {
            //获取学习资料从中抽取一部分试题
            PageableList<DriverLearnDatumDto> learnDatums = this.GetDriverLearnDatums(null, null, 1, 100, role);
            int[] datumIds = this.SiphonRandomDaturmIds(learnDatums);
            if (datumIds.Length <= 0)
            {
                throw new ArgumentException("抽取试题信息失败");
            }
            int correctAmount = examineTestquestionsData.GetDatumCorrectAnswers(datumIds).GetAwaiter().GetResult();
            int errorAmount = examineTestquestionsData.GetDatumErrorAnswers(datumIds).GetAwaiter().GetResult();
            DriverExaminePaperEntity paper = paperData.CheckExistsByAmountsAsync(correctAmount, errorAmount).GetAwaiter().GetResult();
            if (paper == null)
            {
                //生成新的考试试卷
                DriverExaminePaperEntity paperEntity = new DriverExaminePaperEntity
                {
                    CorrectAmount = correctAmount < 0 ? 0 : correctAmount,
                    ErrorAmount = errorAmount < 0 ? 0 : errorAmount,
                    CreateTime = DateTime.Now,
                    EndTime = DateTime.Now,
                    AppliedTo = role
                };
                paper = paperData.InsertAsync(paperEntity).GetAwaiter().GetResult();
            }
            if (paper == null)
            {
                throw new ArgumentException("获取试题信息失败");
            }
            var list = examineTestquestionsData.GetDriverExamineTestQuestionsByPaperId(paper.PaperId).GetAwaiter().GetResult().ToList();
            if (!list.Any())
            {
                var testQuestions = testQuestionAnswerData.GetTestQuestionAnswerByDaturnAnswerIds(datumIds).GetAwaiter().GetResult();
                foreach (var item in learnDatums.Items.Where(s => datumIds.Contains(s.DatumId)))
                {
                    var testQuestion = testQuestions.FirstOrDefault(s => s.DatumAnswerId == item.DatumAnswerId);
                    if (testQuestion != null && !examineTestquestionsData.CheckExistsByQuestionsNoAndPaperId(testQuestion.TestquestionNo, paper.PaperId).GetAwaiter().GetResult())
                    {
                        DriverExamineTestQuestionEntity question = new DriverExamineTestQuestionEntity
                        {
                            PaperId = paper.PaperId,
                            CreateTime = DateTime.Now,
                            DatumTopic = item.DatumTopic,
                            DatumAnswerId = item.DatumAnswerId,
                            DatumId = item.DatumId,
                            TestQuestionNo = testQuestion != null ? testQuestion.TestquestionNo : string.Empty
                        };
                        var newQuestion = examineTestquestionsData.InsertAsync(question).GetAwaiter().GetResult();
                        if (newQuestion != null)
                        {
                            list.Add(newQuestion);
                        }
                    }
                }
            }
            var datats = list.As<IEnumerable<DriverExamineTestQuestionDto>>();
            PageableList<DriverExamineTestQuestionDto> pageDto = new PageableList<DriverExamineTestQuestionDto>
            {
                Count = datats.Count(),
                Items = datats
            };
            return pageDto;
        }

        /// <summary>
        /// 随机抽取一组学习资料
        /// </summary>
        /// <param name="learnDatums">学习资料集合</param>
        /// <returns></returns>
        private int[] SiphonRandomDaturmIds(PageableList<DriverLearnDatumDto> learnDatums)
        {
            int length = learnDatums.Items.Count() < 10 ? learnDatums.Items.Count() : 10;
            int i = 0;
            int[] randMembers = new int[length];
            int[] allDaturmIds = learnDatums.Items.Select(s => s.DatumId).ToArray();
            while (i <= length)
            {
                Random random = new Random((int)DateTime.Now.Ticks);
                int index = random.Next(0, length);
                if (!randMembers.Contains(allDaturmIds[index]))
                {
                    randMembers[i] = allDaturmIds[index];
                    i++;
                }
                if (i == length)
                    break;
            }
            return randMembers;
        }

        /// <summary>
        /// 获取指定试卷的考试题答案信息
        /// </summary>
        /// <param name="paperId">试卷编号</param>
        /// <returns></returns>
        public PageableList<ExamineQuestionAnswerDto> GetExamineQuestionAnswers(long paperId)
        {
            if (!paperData.CheckExistsByIdAsync(paperId).GetAwaiter().GetResult())
            {
                throw new ArgumentException("试卷信息不存在");
            }
            var list = testQuestionAnswerData.GetDriverExamineTestQuestionAnswersByPaperId(paperId).GetAwaiter().GetResult();
            var groupAnswers = list.GroupBy(t => t.TestquestionNo).Select(s => s);
            List<ExamineQuestionAnswerDto> listAnswers = new List<ExamineQuestionAnswerDto>();
            PageableList<ExamineQuestionAnswerDto> pageDto = new PageableList<ExamineQuestionAnswerDto>();
            if (groupAnswers.Any())
            {
                foreach (var group in groupAnswers)
                {
                    ExamineQuestionAnswerDto questionAnswer = new ExamineQuestionAnswerDto();
                    DriverExamineTestQuestionAnswerEntity entity = group.FirstOrDefault() as DriverExamineTestQuestionAnswerEntity;
                    if (entity == null)
                    {
                        continue;
                    }
                    questionAnswer.QuestionsNo = entity.TestquestionNo;
                    List<AnswerDto> answers = new List<AnswerDto>();
                    foreach (var item in list.Where(s => s.TestquestionNo == entity.TestquestionNo))
                    {
                        answers.Add(new AnswerDto
                        {
                            AnswerId = item.DatumAnswerId,
                            AnswerContent = item.AnswerContent,
                            TIndex = item.TIndex

                        });
                    }
                    questionAnswer.Answers = answers.ToArray();
                    listAnswers.Add(questionAnswer);
                }
                pageDto.Count = groupAnswers.Count();
                pageDto.Items = listAnswers.ToArray();
            }
            return pageDto;
        }

        /// <summary>
        /// 生成一份考试成绩表
        /// </summary>
        /// <param name="driverId"></param>
        /// <param name="dto"></param>
        /// <returns></returns>
        public DriverExamineMarkDto CreateExamineMark(long driverId, DriverExamineMarkRequestDto dto)
        {
            DriverExamineMarkEntity result = null;
            var driver = driverData.GetDriverByIdAsync(driverId).GetAwaiter().GetResult();
            if (driver == null)
            {
                throw new ArgumentException("司机信息不存在");
            }
            var paperExists = paperData.CheckExistsByIdAsync(dto.PaperId).GetAwaiter().GetResult();
            if (!paperExists)
            {
                throw new ArgumentException("考试试卷信息不存在");
            }

            DriverExamineMarkEntity entity = new DriverExamineMarkEntity
            {
                Mark = dto.Mark,
                CorrectNumber = dto.CorrectNumber,
                ErrorNumber = dto.ErrorNumber,
                PaperId = dto.PaperId,
                DriverId = driverId,
                CreateTime = DateTime.Now
            };

            var exisitExaminMark = examineMarkData.GetExamineMarkByDriverIdAsync(driverId).GetAwaiter().GetResult();
            if (exisitExaminMark != null)
            {
                entity.ExamineMarkId = exisitExaminMark.ExamineMarkId;
                result = examineMarkData.UpdateMarkAsync(entity).GetAwaiter().GetResult();
            }
            else
            {
                long markId = examineMarkData.InsertAsync(entity).GetAwaiter().GetResult();
                result = examineMarkData.GetDriverExamineMarkByIdAsync(markId).GetAwaiter().GetResult();
            }
            if (result == null)
            {
                return null;

            }

            //判断考试成绩是否合格
            if (result.Mark > 0 && result.Mark >= 60)
            {
                //更新当前司机考试通过
                driver = driverData.TrainPassedAsync(driverId).GetAwaiter().GetResult();
            }
            else
            {
                //更新当前司机考试不通过
                driver = driverData.TrainUnPassedAsync(driverId).GetAwaiter().GetResult();
            }
            if (driver != null)
            {
                this.redisService.Delete(string.Format(this.cacheDriverKeyFormat, driver.DriverId));
            }
            //更新试卷的考试完成时间
            if (result != null)
                paperData.UpdateEndTimeAsync(result.PaperId).GetAwaiter().GetResult();

            return result.As<DriverExamineMarkDto>();
        }
    }
}
